package com.ruoyi.business.task;

import com.ruoyi.business.domain.BusinessTradeConfig;
import com.ruoyi.business.domain.BusinessTradeRecord;
import com.ruoyi.business.dto.DailyReportDTO;
import com.ruoyi.business.enumType.PSIceOrderType;
import com.ruoyi.business.enumType.TriggerType;
import com.ruoyi.business.service.EmailService;
import com.ruoyi.business.service.IBusinessTradeConfigService;
import com.ruoyi.business.service.IBusinessTradeRecordService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.mapper.SysDictDataMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component("businessDailyReportTask")
public class BusinessDailyReportTask {


    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(BusinessDailyReportTask.class);


    @Autowired
    private IBusinessTradeRecordService businessTradeRecordService;

    @Autowired
    private IBusinessTradeConfigService businessTradeConfigService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;



    @Value("${spring.mail.recipient1}")
    private String recipient1;

    @Value("${spring.mail.recipient2}")
    private String recipient2;

    /**
     * 每天交易结束发送日报统计报表到邮箱
     */
    public void sendBusinessDailyReport() {
        logger.info("定时任务--->发送日报表到邮箱开始");

        try {
            List<DailyReportDTO> dailyReportDTOList = new ArrayList<>();
            List<BusinessTradeRecord> openPositionRecordList = new ArrayList<>();

            List<BusinessTradeConfig> businessTradeConfigs = businessTradeConfigService.selectBusinessTradeConfigList(new BusinessTradeConfig());
            Map<Long, BusinessTradeConfig> configMap = businessTradeConfigs.stream().collect(Collectors.toMap(BusinessTradeConfig::getId, Function.identity()));

            List<BusinessTradeRecord> businessTradeRecordList = businessTradeRecordService.selectTodayTradeRecord();
            if (businessTradeRecordList.isEmpty()) {
                return;
            }

            Map<Long, List<BusinessTradeRecord>> openPositionRecordsMap = businessTradeRecordList.stream().filter(item -> TriggerType.AUTO_TAKE_POSITION_TRIGGER.equals(TriggerType.valueOf(item.getTriggerType()))).filter(BusinessTradeRecord::getPositionClosed).collect(Collectors.groupingBy(BusinessTradeRecord::getStrategyId));
            openPositionRecordsMap.forEach((strategyId,openPositionRecords)->{
                // 对开仓单进行统计
                for (BusinessTradeRecord businessTradeRecord : openPositionRecords) {

                    BusinessTradeRecord backBusinessTradeRecord = businessTradeRecordList.stream().filter(item -> businessTradeRecord.getOrderNo().equals(item.getRelatedOrderNo())).findFirst().orElse(null);
                    if(backBusinessTradeRecord==null){
                        logger.error("定时发送日报开仓单获取回向单不存在：orderNo:{}", businessTradeRecord.getOrderNo());
                        continue;
                    }

                    BusinessTradeConfig businessTradeConfig = configMap.get(strategyId);
                    if (Objects.isNull(businessTradeConfig)) {
                        logger.error("定时发送日报开仓单获取策略数据为空：strategyId:{}", businessTradeRecord.getStrategyId());
                        continue;
                    }
                    DailyReportDTO dailyReportDTO = new DailyReportDTO();
                    dailyReportDTO.setStrategyId(strategyId.intValue());
                    dailyReportDTO.setStrategyGroupId(businessTradeRecord.getStrategyGroupId().intValue());
                    dailyReportDTO.setStrategyName(businessTradeRecord.getStrategyName());
                    dailyReportDTO.setSymbol(businessTradeRecord.getStockCode());
                    dailyReportDTO.setDelegateCancle(businessTradeRecord.getDelegateCancle());
                    dailyReportDTO.setDelegateType(businessTradeRecord.getDelegateType());
                    dailyReportDTO.setDelegateCode(businessTradeRecord.getDelegateCode());
                    dailyReportDTO.setPositionAmount(businessTradeRecord.getDealAmount());
                    if(PSIceOrderType.Sell.equals(PSIceOrderType.valueOf(businessTradeRecord.getDelegateType()))){
                        dailyReportDTO.setSaleAmount(backBusinessTradeRecord.getDealAmount());
                        dailyReportDTO.setSellAmount(businessTradeRecord.getDealAmount());
                        dailyReportDTO.setClosePositionWinOrLose(businessTradeRecord.getDealAmount().subtract(backBusinessTradeRecord.getDealAmount()));
                    }
                    if(PSIceOrderType.Buy.equals(PSIceOrderType.valueOf(businessTradeRecord.getDelegateType()))){
                        dailyReportDTO.setSaleAmount(businessTradeRecord.getDealAmount());
                        dailyReportDTO.setSellAmount(backBusinessTradeRecord.getDealAmount());
                        dailyReportDTO.setClosePositionWinOrLose(backBusinessTradeRecord.getDealAmount().subtract(businessTradeRecord.getDealAmount()));
                    }
                    dailyReportDTO.setProfitRate(dailyReportDTO.getClosePositionWinOrLose().divide(businessTradeRecord.getDealAmount(),6,RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                    dailyReportDTOList.add(dailyReportDTO);
                    businessTradeRecord.setProfit(dailyReportDTO.getClosePositionWinOrLose());
                    businessTradeRecord.setProfitRate(dailyReportDTO.getProfitRate());

                    openPositionRecordList.add(businessTradeRecord);
                }
            });

            if(!CollectionUtils.isEmpty(openPositionRecordList)){
                for (BusinessTradeRecord businessTradeRecord : openPositionRecordList) {
                    businessTradeRecordService.updateBusinessTradeRecord(businessTradeRecord);
                }
            }else{
                logger.info("定时任务执行日报发送邮箱发送数据为空：openPositionRecordList.size:{}",openPositionRecordList.size());
                return;
            }
            Map<Integer, List<DailyReportDTO>> strategyGroupIdMap = dailyReportDTOList.stream().collect(Collectors.groupingBy(DailyReportDTO::getStrategyGroupId));

            // 按照策略组发送日报数据
            List<String> filePaths = new ArrayList<>();
            for (Map.Entry<Integer, List<DailyReportDTO>> listEntry : strategyGroupIdMap.entrySet()) {
                Integer strategyGroupId = listEntry.getKey();
                List<DailyReportDTO> value = listEntry.getValue();
                Map<Integer, List<DailyReportDTO>> strategyIdRecordMap = value.stream().collect(Collectors.groupingBy(DailyReportDTO::getStrategyId));

                List<DailyReportDTO> reportDTOS = new ArrayList<>();
                strategyIdRecordMap.forEach((strategyId,dailyReports)->{
                    DailyReportDTO dailyReportDTO = new DailyReportDTO();
                    dailyReportDTO.setStrategyGroupId(strategyGroupId);
                    dailyReportDTO.setStrategyId(strategyId);
                    BusinessTradeConfig businessTradeConfig = configMap.get(Long.valueOf(strategyId));
                    if(Objects.nonNull(businessTradeConfig)){
                        dailyReportDTO.setClientName(businessTradeConfig.getClientName());
                    }

                    dailyReportDTO.setStrategyName(dailyReports.stream().map(DailyReportDTO::getStrategyName).filter(Objects::nonNull).findAny().orElse(null));
                    dailyReportDTO.setSymbol(dailyReports.stream().map(DailyReportDTO::getSymbol).findFirst().orElse(null));

                    dailyReportDTO.setSaleAmount(dailyReports.stream().map(DailyReportDTO::getSaleAmount).reduce(BigDecimal.ZERO,BigDecimal::add).divide(new BigDecimal(10000),6,RoundingMode.HALF_UP));
                    dailyReportDTO.setSellAmount(dailyReports.stream().map(DailyReportDTO::getSellAmount).reduce(BigDecimal.ZERO,BigDecimal::add).divide(new BigDecimal(10000),6,RoundingMode.HALF_UP));
                    // 手续费 元
                    dailyReportDTO.setHandlingFee(dailyReportDTO.getSaleAmount().add(dailyReportDTO.getSellAmount()).multiply(new BigDecimal("0.6")));
                    dailyReportDTO.setCancelPositionTimes((int) dailyReports.stream().filter(DailyReportDTO::getDelegateCancle).count());
                    dailyReportDTO.setProfitAmount(dailyReportDTO.getSellAmount().subtract(dailyReportDTO.getSaleAmount()));
                    BigDecimal positionAmountAll = dailyReports.stream().map(DailyReportDTO::getPositionAmount).reduce(BigDecimal.ZERO, BigDecimal::add).divide(new BigDecimal(10000),6,RoundingMode.HALF_UP);
                    long winTimes = dailyReports.stream().filter(item -> item.getClosePositionWinOrLose().compareTo(BigDecimal.ZERO) > 0).count();
                    dailyReportDTO.setOpenPositionTimes( dailyReports.stream().collect(Collectors.groupingBy(DailyReportDTO::getDelegateCode)).size());
                    dailyReportDTO.setProfitRate(dailyReportDTO.getProfitAmount().divide(positionAmountAll,6,RoundingMode.HALF_UP).multiply(new BigDecimal(100)));
                    dailyReportDTO.setProfitTimesRate(new BigDecimal(winTimes).divide(new BigDecimal(dailyReports.size()),2,RoundingMode.HALF_UP));
                    dailyReportDTO.setSummaryDate(new Date());
                    reportDTOS.add(dailyReportDTO);
                });

                BusinessTradeConfig businessTradeConfigQuery = new BusinessTradeConfig();
                businessTradeConfigQuery.setStrategyGroupId(Long.valueOf(strategyGroupId));
                businessTradeConfigQuery.setStatus(0);
                List<BusinessTradeConfig> businessTradeConfigList = businessTradeConfigService.selectBusinessTradeConfigList(businessTradeConfigQuery);
                for (BusinessTradeConfig businessTradeConfig : businessTradeConfigList) {

                    Date openTime = null;
                    try {
                        openTime = DateUtils.parseDate("09:30:00", DateUtils.HH_MM_SS);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    Date openTimeDelay = DateUtils.addMinutes(openTime, businessTradeConfig.getPositionDelayMinute());
                    businessTradeConfig.setOpenPositionTime(openTimeDelay);
                    businessTradeConfig.setTradeAmountPerLimit(businessTradeConfig.getTradeAmountPerLimit().divide(new BigDecimal(10000),6,RoundingMode.HALF_UP));
                    businessTradeConfig.setTradeAmountLimit(businessTradeConfig.getTradeAmountLimit().divide(new BigDecimal(10000),6,RoundingMode.HALF_UP));
                    businessTradeConfig.setProfitStopType(businessTradeConfig.getDynamicStopProfitRate()==null?"静态止盈":"动态止盈");
                    businessTradeConfig.setDynamicStopProfitBeforeRate(businessTradeConfig.getStaticStopProfitRate());
                    businessTradeConfig.setClosePositionTime(DateUtils.parseDate("14:50:00", DateUtils.HH_MM_SS));
                }

                String groupLabel = sysDictDataMapper.selectDictLabel("business_strategy_group", String.valueOf(strategyGroupId));

                String filePath1 = "";
                String filePath2 = "";
                ExcelUtil<DailyReportDTO> util = new ExcelUtil<DailyReportDTO>(DailyReportDTO.class);
                AjaxResult ajaxResult = util.exportExcel(reportDTOS, "策略交易详情");
                if(200==(int)ajaxResult.get(AjaxResult.CODE_TAG)){
                    filePath1 = util.getAbsoluteFile((String) ajaxResult.get(AjaxResult.MSG_TAG));
                }

                ExcelUtil<BusinessTradeConfig> util2 = new ExcelUtil<BusinessTradeConfig>(BusinessTradeConfig.class);
                AjaxResult ajaxResult2 = util2.exportExcel(businessTradeConfigList, "策略配置详情");
                if(200==(int)ajaxResult2.get(AjaxResult.CODE_TAG)){
                    filePath2 = util2.getAbsoluteFile((String) ajaxResult2.get(AjaxResult.MSG_TAG));
                }
                ExcelUtil<Object> utilMerge = new ExcelUtil<>(Object.class);

                AjaxResult ajaxResultMerge = utilMerge.mergeSheetAndExportExcel(filePath1, filePath2, groupLabel+".xlsx");
                if(200==(int)ajaxResultMerge.get(AjaxResult.CODE_TAG)){
                  String  outFilePath = utilMerge.getAbsoluteFile((String) ajaxResultMerge.get(AjaxResult.MSG_TAG));
                  filePaths.add(outFilePath);
                }

            }
            emailService.sendEmailWithAttachment(new String[]{recipient1,recipient2}, DateUtils.getDate() +" 开仓交易数据", "（荣浩华）请打开附件查看当日交易明细", filePaths.toArray(new String[0]));

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("定时任务执行日报发送邮箱失败：", e);
        }
        logger.info("定时任务--->发送日报表到邮箱结束");
    }
}
